PTA 5-2 Reversing Linked List (25) [法一] - 线性表 - 链表反转 (PAT 1074)
题目:http://www.patest.cn/contests/pat-a-practise/1074
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:
00100 6 4 //第一行:链表的首地址add,结点个数n,每隔k个进行一次反转 00000 4 99999 //后面n行:结点的地址address,数据data,下一个结点的地址next 00100 1 12309 68237 6 -1 33218 3 00000 99999 5 68237 12309 2 33218
Sample Output:
00000 4 33218 //反转之后的结果 33218 3 12309 12309 2 00100 00100 1 99999 99999 5 68237 68237 6 -1
题目大意:
反转单链表,给定常数K和单链表L,要求按每K个节点反转单链表,如:L: 1->2->3->4->5->6 K=3,输出:3->2->1->6->5->4,如果K=4,输出:4->3->2->1->5->6.
特殊情况:
1. 有其他链表干扰(即有多个-1出现):找链表有效长度
2. k=1 或者 k=n :不变 或者 全部逆序
3. 需逆序的起点大于有效长度 : 直接输出原链表
推荐测试:
1. k=1或者k=n:
00100 6 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
2. 有其他链表干扰(即有多个-1出现):
00100 6 2
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 -1
99999 5 68237
12309 2 33218
- 定义结构
struct Node { int iData; int iNext; }; const int iMaxLen = 100004; int iHead; //!首地址 int N, K; Node NodeList[iMaxLen];
- paixu():
1. 找有效长度:判断next是否遇到-1
2. 若需逆序的起点 > 有效长度(k > iEffectiveLength):doPrint(iHead)
3. 更新结点总数 N 为有效长度 iEffectiveLength
K>1:
4. 初始化新链表(反转后)的首尾地址
// iNewHead,iLastTail 表示新链表(反转后)的首尾地址 // iTheHead,iTheTail 表示链表中反转的每一小节的开头和结尾 reverseK(iHead, K, &iTheHead, &iTheTail); iNewHead = iTheHead; iLastTail = iTheTail;
5. 计算反转次数:
iReserveCount = N/K – 1
6. 每K个翻转一次
for(int i = 0; i < iReverseCount; ++i) { reverseK(NodeList[iTheTail].iNext, K, &iTheHead, &iTheTail); NodeList[iLastTail].iNext = iTheHead; iLastTail = iTheTail; }
K<=1:
iNewHead = iHead;
7.输出链表:
doPrint(iNewHead);
- reverseK():
从 iStartHead 开始反转k个元素(原理即单链表反转)
int reverseK(int iStartHead, int iK, int *pHead, int *pTail) //iStartHead:每一小节开始反转的结点 //node1,node2,nodeTmp:可看作反转所需的三个指针
完整代码:
#include <cstdio> struct Node { int iData; int iNext; }; const int iMaxLen = 100004; int iHead; //!首地址 int N, K; Node NodeList[iMaxLen]; void doPrint(int iNodeAdd) { while(iNodeAdd!=-1){ if(NodeList[iNodeAdd].iNext == -1){ printf("%.5d %d -1\n",iNodeAdd,NodeList[iNodeAdd].iData); break; } printf("%.5d %d %.5d\n",iNodeAdd, NodeList[iNodeAdd].iData, NodeList[iNodeAdd].iNext); iNodeAdd = NodeList[iNodeAdd].iNext; } } //!从iStartHead开始反转k个元素 int reverseK(int iStartHead, int iK, int *pHead, int *pTail) { //!只有一个节点 if(-1 == iStartHead || iK <= 1) return -1; if(2 == iK){ int node1 = iStartHead; int node2 = NodeList[iStartHead].iNext; NodeList[node1].iNext = NodeList[node2].iNext; NodeList[node2].iNext = node1; *pHead = node2; *pTail = node1; return 0; } *pTail = iStartHead; int node1 = iStartHead; int node2 = NodeList[iStartHead].iNext; int nodeTmp = -1; for(int i = 0; i < iK - 1; ++i){ nodeTmp = NodeList[node2].iNext; NodeList[node2].iNext = node1; node1 = node2; node2 = nodeTmp; } *pHead = node1; NodeList[*pTail].iNext = node2; return 0; } void paixu() { int iNodeTmp = iHead; //!找有效结点的长度:即判断next是否遇到-1 int iEffectiveLength = 1; while(-1 != NodeList[iNodeTmp].iNext) { ++iEffectiveLength; iNodeTmp = NodeList[iNodeTmp].iNext; } //!需逆序的起点大于有效长度 if(K > iEffectiveLength){ //!直接输出当前没有逆序的结点 doPrint(iHead); } //!有效长度覆盖输入的结点总个数 N = iEffectiveLength; int iNewHead; if(K > 1) { int iTheHead, iTheTail; int iLastTail; //!first init reverse to decide the new head reverseK(iHead, K, &iTheHead, &iTheTail); iNewHead = iTheHead; iLastTail = iTheTail; int iReverseCount = N / K - 1; //!反转次数 for(int i = 0; i < iReverseCount; ++i) { reverseK(NodeList[iTheTail].iNext, K, &iTheHead, &iTheTail); NodeList[iLastTail].iNext = iTheHead; iLastTail = iTheTail; } } else iNewHead = iHead; doPrint(iNewHead); } int main() { //!初始化 data和next都初始化为0 for(int i = 0; i < iMaxLen; ++i) { NodeList[i].iData = 0; NodeList[i].iNext = -1; } //!输入首地址,结点总数,需逆序到的数 scanf("%d %d %d", &iHead, &N, &K); int iSingleNodeAddress, iSingleNodeData, iSingleNodeNext; for(int i = 0; i < N; ++i) { scanf("%d %d %d", &iSingleNodeAddress, &iSingleNodeData, &iSingleNodeNext); NodeList[iSingleNodeAddress].iData = iSingleNodeData; NodeList[iSingleNodeAddress].iNext = iSingleNodeNext; } paixu(); return 0; }